home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 21 Ambient Occlusion / Ssao / Shaders / Ssao.hlsl < prev    next >
Encoding:
Text File  |  2016-03-02  |  6.3 KB  |  200 lines

  1. //=============================================================================
  2. // Ssao.hlsl by Frank Luna (C) 2015 All Rights Reserved.
  3. //=============================================================================
  4.  
  5. cbuffer cbSsao : register(b0)
  6. {
  7.     float4x4 gProj;
  8.     float4x4 gInvProj;
  9.     float4x4 gProjTex;
  10.     float4   gOffsetVectors[14];
  11.  
  12.     // For SsaoBlur.hlsl
  13.     float4 gBlurWeights[3];
  14.  
  15.     float2 gInvRenderTargetSize;
  16.  
  17.     // Coordinates given in view space.
  18.     float    gOcclusionRadius;
  19.     float    gOcclusionFadeStart;
  20.     float    gOcclusionFadeEnd;
  21.     float    gSurfaceEpsilon;
  22. };
  23.  
  24. cbuffer cbRootConstants : register(b1)
  25. {
  26.     bool gHorizontalBlur;
  27. };
  28.  
  29. // Nonnumeric values cannot be added to a cbuffer.
  30. Texture2D gNormalMap    : register(t0);
  31. Texture2D gDepthMap     : register(t1);
  32. Texture2D gRandomVecMap : register(t2);
  33.  
  34. SamplerState gsamPointClamp : register(s0);
  35. SamplerState gsamLinearClamp : register(s1);
  36. SamplerState gsamDepthMap : register(s2);
  37. SamplerState gsamLinearWrap : register(s3);
  38.  
  39. static const int gSampleCount = 14;
  40.  
  41. static const float2 gTexCoords[6] =
  42. {
  43.     float2(0.0f, 1.0f),
  44.     float2(0.0f, 0.0f),
  45.     float2(1.0f, 0.0f),
  46.     float2(0.0f, 1.0f),
  47.     float2(1.0f, 0.0f),
  48.     float2(1.0f, 1.0f)
  49. };
  50.  
  51. struct VertexOut
  52. {
  53.     float4 PosH : SV_POSITION;
  54.     float3 PosV : POSITION;
  55.     float2 TexC : TEXCOORD0;
  56. };
  57.  
  58. VertexOut VS(uint vid : SV_VertexID)
  59. {
  60.     VertexOut vout;
  61.  
  62.     vout.TexC = gTexCoords[vid];
  63.  
  64.     // Quad covering screen in NDC space.
  65.     vout.PosH = float4(2.0f*vout.TexC.x - 1.0f, 1.0f - 2.0f*vout.TexC.y, 0.0f, 1.0f);
  66.  
  67.     // Transform quad corners to view space near plane.
  68.     float4 ph = mul(vout.PosH, gInvProj);
  69.     vout.PosV = ph.xyz / ph.w;
  70.  
  71.     return vout;
  72. }
  73.  
  74. // Determines how much the sample point q occludes the point p as a function
  75. // of distZ.
  76. float OcclusionFunction(float distZ)
  77. {
  78.     //
  79.     // If depth(q) is "behind" depth(p), then q cannot occlude p.  Moreover, if 
  80.     // depth(q) and depth(p) are sufficiently close, then we also assume q cannot
  81.     // occlude p because q needs to be in front of p by Epsilon to occlude p.
  82.     //
  83.     // We use the following function to determine the occlusion.  
  84.     // 
  85.     //
  86.     //       1.0     -------------\
  87.     //               |           |  \
  88.     //               |           |    \
  89.     //               |           |      \ 
  90.     //               |           |        \
  91.     //               |           |          \
  92.     //               |           |            \
  93.     //  ------|------|-----------|-------------|---------|--> zv
  94.     //        0     Eps          z0            z1        
  95.     //
  96.     
  97.     float occlusion = 0.0f;
  98.     if(distZ > gSurfaceEpsilon)
  99.     {
  100.         float fadeLength = gOcclusionFadeEnd - gOcclusionFadeStart;
  101.         
  102.         // Linearly decrease occlusion from 1 to 0 as distZ goes 
  103.         // from gOcclusionFadeStart to gOcclusionFadeEnd.    
  104.         occlusion = saturate( (gOcclusionFadeEnd-distZ)/fadeLength );
  105.     }
  106.     
  107.     return occlusion;    
  108. }
  109.  
  110. float NdcDepthToViewDepth(float z_ndc)
  111. {
  112.     // z_ndc = A + B/viewZ, where gProj[2,2]=A and gProj[3,2]=B.
  113.     float viewZ = gProj[3][2] / (z_ndc - gProj[2][2]);
  114.     return viewZ;
  115. }
  116.  
  117. float4 PS(VertexOut pin) : SV_Target
  118. {
  119.     // p -- the point we are computing the ambient occlusion for.
  120.     // n -- normal vector at p.
  121.     // q -- a random offset from p.
  122.     // r -- a potential occluder that might occlude p.
  123.  
  124.     // Get viewspace normal and z-coord of this pixel.  
  125.     float3 n = normalize(gNormalMap.SampleLevel(gsamPointClamp, pin.TexC, 0.0f).xyz);
  126.     float pz = gDepthMap.SampleLevel(gsamDepthMap, pin.TexC, 0.0f).r;
  127.     pz = NdcDepthToViewDepth(pz);
  128.  
  129.     //
  130.     // Reconstruct full view space position (x,y,z).
  131.     // Find t such that p = t*pin.PosV.
  132.     // p.z = t*pin.PosV.z
  133.     // t = p.z / pin.PosV.z
  134.     //
  135.     float3 p = (pz/pin.PosV.z)*pin.PosV;
  136.     
  137.     // Extract random vector and map from [0,1] --> [-1, +1].
  138.     float3 randVec = 2.0f*gRandomVecMap.SampleLevel(gsamLinearWrap, 4.0f*pin.TexC, 0.0f).rgb - 1.0f;
  139.  
  140.     float occlusionSum = 0.0f;
  141.     
  142.     // Sample neighboring points about p in the hemisphere oriented by n.
  143.     for(int i = 0; i < gSampleCount; ++i)
  144.     {
  145.         // Are offset vectors are fixed and uniformly distributed (so that our offset vectors
  146.         // do not clump in the same direction).  If we reflect them about a random vector
  147.         // then we get a random uniform distribution of offset vectors.
  148.         float3 offset = reflect(gOffsetVectors[i].xyz, randVec);
  149.     
  150.         // Flip offset vector if it is behind the plane defined by (p, n).
  151.         float flip = sign( dot(offset, n) );
  152.         
  153.         // Sample a point near p within the occlusion radius.
  154.         float3 q = p + flip * gOcclusionRadius * offset;
  155.         
  156.         // Project q and generate projective tex-coords.  
  157.         float4 projQ = mul(float4(q, 1.0f), gProjTex);
  158.         projQ /= projQ.w;
  159.  
  160.         // Find the nearest depth value along the ray from the eye to q (this is not
  161.         // the depth of q, as q is just an arbitrary point near p and might
  162.         // occupy empty space).  To find the nearest depth we look it up in the depthmap.
  163.  
  164.         float rz = gDepthMap.SampleLevel(gsamDepthMap, projQ.xy, 0.0f).r;
  165.         rz = NdcDepthToViewDepth(rz);
  166.  
  167.         // Reconstruct full view space position r = (rx,ry,rz).  We know r
  168.         // lies on the ray of q, so there exists a t such that r = t*q.
  169.         // r.z = t*q.z ==> t = r.z / q.z
  170.  
  171.         float3 r = (rz / q.z) * q;
  172.         
  173.         //
  174.         // Test whether r occludes p.
  175.         //   * The product dot(n, normalize(r - p)) measures how much in front
  176.         //     of the plane(p,n) the occluder point r is.  The more in front it is, the
  177.         //     more occlusion weight we give it.  This also prevents self shadowing where 
  178.         //     a point r on an angled plane (p,n) could give a false occlusion since they
  179.         //     have different depth values with respect to the eye.
  180.         //   * The weight of the occlusion is scaled based on how far the occluder is from
  181.         //     the point we are computing the occlusion of.  If the occluder r is far away
  182.         //     from p, then it does not occlude it.
  183.         // 
  184.         
  185.         float distZ = p.z - r.z;
  186.         float dp = max(dot(n, normalize(r - p)), 0.0f);
  187.  
  188.         float occlusion = dp*OcclusionFunction(distZ);
  189.  
  190.         occlusionSum += occlusion;
  191.     }
  192.     
  193.     occlusionSum /= gSampleCount;
  194.     
  195.     float access = 1.0f - occlusionSum;
  196.  
  197.     // Sharpen the contrast of the SSAO map to make the SSAO affect more dramatic.
  198.     return saturate(pow(access, 6.0f));
  199. }
  200.